Attaching events in Svelte

Posted on 2023-02-02 by

henrikvilhelmberglund

In vanilla JS we do something like this:

let h1 = document.querySelector("h1");
h1.addEventListener("click", () => { });

but in Svelte we can add event listeners directly in the markup .

(will show in the console)
<script>
  function handleClick() {
    console.log("you clicked!")
  }
</script>

<button on:click={handleClick}>Click me</button> (will show in the console)

Of course it's also possible to use arrow functions.

(will show in the console)
<button on:click={() => console.log("you clicked me!!")}>Click me</button> (will show in the console)

If the component is removed from the DOM the event listeners will automatically be cleaned up .

Event modifiers

When we have forms in HTML we may want to use the JS event.preventDefault(); .

In Svelte we can have that as an event modifier . After the event name we can add | and preventDefault to get the same effect without writing code in the script tag.

(will show in the console)
<script>
  function handleClick() {
    console.log("you clicked!")
  }
</script>

<button on:click|preventDefault={handleClick}>Click me</button> (will show in the console)

There are also other modifiers like stopPropagation to prevent bubbling,

Without |stopPropagation
Parent
Child

With |stopPropagation
Parent
Child
Without |stopPropagation
<div on:click={() => console.log("Parent")}>
  Parent
  <div on:click={() => console.log("Child")}>
    <!-- output is "Child" then "Parent" -->
    Child
  </div>
</div>

<br>

With |stopPropagation
<div on:click={() => console.log("Parent")}>
  Parent
  <div on:click|stopPropagation={() => console.log("Child")}>
    <!-- output is only "Child" since we stopped propagation -->
    Child
  </div>
</div>

and the .addEventListener() third options arguments are also available, for example capture to trigger the event in the capture phase.

Without |capture
Parent
Child
With |capture
Parent
Child
Without |capture
<div on:click={() => console.log("Parent")}>
  Parent
  <div on:click={() => console.log("Child")}>
    <!-- output is "Child" then "Parent" -->
    Child
  </div>
</div>

With |capture
<div on:click|capture={() => console.log("Parent")}>
  Parent
  <div on:click={() => console.log("Child")}>
    <!-- output is "Parent" then "Child" because of |capture -->
    Child
  </div>
</div>

Other possible event modifiers are once , passive , nonpassive , trusted and self .

Self will only trigger if the event.target is the element itself .

Without |self
Parent
Child
With |self
Parent
Child
Without |self
<div on:click={() => console.log("Parent")}>
  Parent
  <div on:click={() => console.log("Child")}>
    <!-- output is "Child" then "Parent" -->
    Child
  </div>
</div>

With |self
<div on:click|self={() => console.log("Parent")}>
  Parent
  <div on:click={() => console.log("Child")}>
    <!-- output is only "Child" because event.target is not the parent div when clicking the child -->
    Child
  </div>
</div>